package com.warmheart.base.filter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

/**
 * 
 * @ClassName: ParamLogResponseWrapper
 * @Description: 响应日志包装类
 * @author ZhangJianyang
 * @date 2025-06-16 09:37:02
 *
 */
public class ParamLogResponseWrapper extends HttpServletResponseWrapper {

    /**
     * 自定义字节数组输出流
     */
    private ByteArrayOutputStream buffer = null;

    /**
     * 自定义输出流
     */
    private ServletOutputStream out = null;

    /**
     * 自定义字符输出流
     */
    private PrintWriter writer = null;

    public ParamLogResponseWrapper(HttpServletResponse response) {
        // 包装原始响应
        super(response);
        // 初始化自定义字节数组输出流
        buffer = new ByteArrayOutputStream();
        // 初始化自定义输出流
        out = new WapperedOutputStream(buffer);
        // 初始化自定义字符输出流
        writer = new PrintWriter(new OutputStreamWriter(buffer, StandardCharsets.UTF_8));
    }

    /**
     * 
     * @ClassName: WapperedOutputStream
     * @Description: 自定义输出流（包装原有的输出流）
     * @author ZhangJianyang
     * @date 2025-06-16 09:37:02
     *
     */
    private class WapperedOutputStream extends ServletOutputStream {

        /**
         * 自定义字节数组输出流
         */
        private ByteArrayOutputStream bos = null;

        public WapperedOutputStream(ByteArrayOutputStream stream) {
            this.bos = stream;
        }

        @Override
        public void write(int b) throws IOException {
            // 数据写入自定义字节数组输出流
            this.bos.write(b);
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {

        }

        @Override
        public boolean isReady() {
            return false;
        }

    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        // 原有的输出流重写为自定义输出流
        return this.out;
    }

    /**
     * 当获取字符输出流时，实际获取的是我们自己包装的字符输出流
     */
    @Override
    public PrintWriter getWriter() {
        // 原有的字符输出流重写为自定义字符输出流
        return this.writer;
    }

    @Override
    public void flushBuffer() throws IOException {
        // 重写缓存刷新方法
        // 刷新自定义字节数组输出流
        if (this.buffer != null) {
            this.buffer.flush();
        }
        // 刷新自定义输出流
        if (this.out != null) {
            this.out.flush();
        }
        // 刷新自定义字符输出流
        if (this.writer != null) {
            this.writer.flush();
        }
    }

    /**
     * 
     * @Title: close
     * @Description: 各种自定义流关闭方法
     * @author ZhangJianyang
     * @throws IOException
     */
    public void close() throws IOException {
        // 关闭自定义字符输出流
        if (this.writer != null) {
            this.writer.close();
        }
        // 关闭自定义输出流
        if (this.out != null) {
            this.out.close();
        }
        // 关闭自定义字节数组输出流
        if (this.buffer != null) {
            this.buffer.close();
        }
    }

    /**
     * 重置自定义字节数组输出流
     */
    @Override
    public void reset() {
        // 这里重置自定义字节数组输出流而不是原有的字节数组输出流，因为数据存在于自定义字节数组输出流
        this.buffer.reset();
    }

    // 重新写出数据，同时打印响应日志
    public void reWrite(Logger logger) throws Exception {
        // 缓存全部写入自定义输出流
        this.flushBuffer();
        // 判断内容类型，二进制流数据和字符串类型数据处理方式有区别
        String resContentType = this.getContentType();
        logger.info("响应内容类型：" + resContentType);
        if (StringUtils.isNotBlank(resContentType) && resContentType.contains("application/octet-stream")) {
            // 获取二进制数据
            byte[] resBytes = this.buffer.toByteArray();
            logger.info("当前返回值为二进制流，不再输出响应信息");
            // 使用原有的响应实类进行操作
            // 写出二进制数据
            this.getResponse().getOutputStream().write(resBytes);
            // 缓存全部写出
            this.getResponse().flushBuffer();
            // 关闭输出流
            this.getResponse().getOutputStream().close();
        } else if (this.getStatus() == 200) {
            // 获取字符串数据
            String resString = this.buffer.toString("UTF-8");
            // 记录返回值信息
            logger.info("返回值：" + resString);
            // 使用原有的响应实类进行操作
            // 写出字符串数据
            this.getResponse().getWriter().write(resString);
            // 缓存全部写出
            this.getResponse().flushBuffer();
            // 关闭输出流
            this.getResponse().getWriter().close();
        }
        // 关闭自定义输出流
        this.close();
    }
}